﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MazeNet.Communication
{
    /// <summary>
    /// EventHandler fuer MazeNetEvents
    /// </summary>
    public class MazeNetHandler
    {
        #region Member

        private MazeNetClient _mClient;
        private PlayerBase _mPlayer;
        private AwaitMoveMessageType _mLastMoveMsg;

        #endregion

        /// <summary>
        /// Erstellt einen neuen MazeNetHandler
        /// </summary>
        /// <param name="_uClient">MazeNetClient der mit dem Handler verknuepft wird</param>
        /// <param name="_uPlayer">Ein Spieler oder eine KI</param>
        public MazeNetHandler(MazeNetClient _uClient, PlayerBase _uPlayer)
        {
            _mClient = _uClient;
            _mPlayer = _uPlayer;

            _mClient.OnMessageReceived += HandleIncominMessage;
        }

        /// <summary>
        /// Kuemmert sich um das richtige Behandeln der Nachrichten vom Server
        /// </summary>
        /// <param name="sender">Der Client der gesendet hat, idR. = _mClient</param>
        /// <param name="e">Das MazeNetEvent mit dem MazeCom Objekt</param>
        private void HandleIncominMessage(object sender, MazeNetEventArgs e)
        {
            switch (e.MazeComMessage.mcType)
            {
                case MazeComType.ACCEPT:
                    HandleAccept((AcceptMessageType) e.MazeComMessage.Item);
                    break;
                case MazeComType.AWAITMOVE:
                    HandleAwaitMove(((AwaitMoveMessageType)e.MazeComMessage.Item));
                    break;
                case MazeComType.DISCONNECT:
                    HandleDisconnet();
                    break;
                case MazeComType.LOGINREPLY:
                    HandleLoginReply();
                    break;
                case MazeComType.WIN:
                    HandleWin((WinMessageType)e.MazeComMessage.Item);
                    break;
            }
        }

        /// <summary>
        /// Fuehrt den Disconnect aus, wenn der Client sich noch nicht 
        /// selbststaendig abgemeldet hat.
        /// </summary>
        private void HandleDisconnet()
        {
            _mClient.Disconnect();
            Console.WriteLine("Verbindung zu Server wurde getrennt.");
        }

        /// <summary>
        /// Zeigt die ID des Gewinners an und meldet sich vom Server ab. 
        /// </summary>
        /// <param name="_uWinnerType">Gewinnnachricht</param>
        private void HandleWin(WinMessageType _uWinnerType)
        {
            Console.WriteLine(string.Format("Gewonnen hat: {0}",
                                            _uWinnerType.winner.Value));
            _mClient.Disconnect();
        }

        /// <summary>
        /// Gibt auf der Konsole aus, dass der Client sich erfolgreich verbunden hat
        /// </summary>
        private void HandleLoginReply()
        {
            _mPlayer.Id = _mClient.Id;
            Console.WriteLine("Erfolgreich mit Server verbunden.");
        }

        /// <summary>
        /// Holt den Zug vom Spieler/der KI und uebergibt ihn dem Client zum Senden.
        /// </summary>
        /// <param name="_uBoard">Die AwaitMove Nachricht vom Server mit Spielbrett und Schatz</param>
        private void HandleAwaitMove(AwaitMoveMessageType _uAwaitMoveMsg)
        {
            //Nachricht speichern falls Fehler auftreten
            _mLastMoveMsg = _uAwaitMoveMsg;

            //MaseCom Objekt erstellen und dessen Werte setzen.
            MazeCom _lMazeCom = new MazeCom();
            _lMazeCom.id = _mClient.Id;

            //_mPlayer berechnet den Zug mit den Informationen der Nachricht
            _lMazeCom.Item = _mPlayer.CalculateMove(_uAwaitMoveMsg);
            _lMazeCom.mcType = MazeComType.MOVE;

            //Die Nachricht wird zum Senden an den Client übergeben.
            _mClient.SendMazeCom(_lMazeCom);
        }

        /// <summary>
        /// Behandelt moegliche Fehler die in der AcceptNachricht vom Server angegeben werden
        /// </summary>
        /// <param name="_uAcceptMsg">die Accept Nachricht des Servers</param>
        private void HandleAccept(AcceptMessageType _uAcceptMsg)
        {
            if (!_uAcceptMsg.accept)
            {
                switch (_uAcceptMsg.errorCode)
                {
                        //Es wurde noch kein Zug durchgefuehrt -> sende einen Zug
                    case ErrorType.AWAIT_MOVE:
                        HandleAwaitMove(_mLastMoveMsg);
                        break;
                        //Es wurde ein falscher Zug durchgefuehrt -> sende einen neuen Zug
                    case ErrorType.ILLEGAL_MOVE:
                        HandleAwaitMove(_mLastMoveMsg);
                        break;
                        //Es fehlt wurde noch kein Login durchgefuehrt -> logge dich ein
                    case ErrorType.AWAIT_LOGIN:
                        _mClient.LogIn("Gnocchi");
                        break;

                }
            }
        }
    }
}
